home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
tools
/
cie.lha
/
cie
/
etags++
/
hier++.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-21
|
9KB
|
386 lines
////////////////////////////////////////////////////////////////////////////////
// hier++.c
//
// This program reads in C++ code and generates a "hier" file that displays the
// class hierarchy. You can then use the GNU Emacs hier-mode for traversing the
// hierarchy and extracting information from your TAGS (if generated by etags++).
//
// Note that this program is built on the same quick-and-dirty "fuzzy" parser
// that etags++ was, and will suffer the same ability to be fooled sometimes.
//
// Author: Brian M. Kennedy
// (C) Copyright 1993, Intellection Inc.
// Permission is granted to use, copy, or modify this code as long as this author and
// copyright notice is maintained in all copies.
//
// Note:
// This is quick, hack code that was not written to be modifiable or maintainable -- beware!!
// I would not allow code such as this into our product! But it is okay for a quick tool hack.
// If you are a user, I hope you enjoy it. If you are modifier, my apologies ;-(
#include "c++file.c"
////////////////////////////////////////////////////////////////////////////////
struct Element;
struct Element_Link
{
Element* element;
Element_Link* next;
Element_Link (Element* element_arg, Element_Link* next_arg = 0);
};
Element_Link::
Element_Link (Element* element_arg, Element_Link* next_arg)
:element(element_arg), next(next_arg)
{}
////////////////////////////////////////////////////////////////////////////////
struct Element
{
const char* name;
Element_Link* parents;
Element_Link* children;
Element (const C_File_Pos& name_pos);
static unsigned hash (const C_File_Pos& name);
unsigned hash () const;
Element_Link* inc_parents (Element* parent)
{ return parents = new Element_Link(parent, parents); }
Element_Link* inc_children (Element* child)
{ return children = new Element_Link(child, children); }
void print (ostream& os, unsigned indent) const;
};
Element::
Element (const C_File_Pos& name_pos)
:name(0), parents(0), children(0)
{
char* copy = new char [name_pos.length + 1];
strncpy(copy, name_pos.chars(), name_pos.length);
copy[name_pos.length] = 0;
name = copy;
}
unsigned Element::
hash (const C_File_Pos& name)
{
unsigned h = 0;
const char* s = name.chars();
for(unsigned i = 0; i < name.length; ++i, ++s)
h = (h << 2) + (unsigned char)(*s);
return h;
}
unsigned Element::
hash () const
{
unsigned h = 0;
for(const char* s = name; *s; ++s)
h = (h << 2) + (unsigned char)(*s);
return h;
}
const char blank_string [] = " ";
inline const char*
blanks (unsigned n)
// Returns a string of 'n' blanks
{ return blank_string + sizeof(blank_string) - n - 1; }
void Element::
print (ostream& os, unsigned indent) const
{
os << blanks(indent) << "* " << name << " ";
for(Element_Link* link = parents; link; link = link->next)
os << " :" << link->element->name;
os << "\n";
for(link = children; link; link = link->next)
link->element->print(os, indent+2);
}
////////////////////////////////////////////////////////////////////////////////
struct Hierarchy
{
unsigned size;
Element_Link** table;
Hierarchy (unsigned symbols);
Element* operator () (const C_File_Pos& name) const;
Hierarchy& inc (Element* element);
Hierarchy& inc (const C_File_Pos& name) { return inc(new Element(name)); }
void print (ostream& os);
};
Hierarchy::
Hierarchy (unsigned symbols)
:size(2*symbols + 1), table(new Element_Link* [size])
{
for(unsigned i = 0; i < size; ++i)
table[i] = 0;
}
Element* Hierarchy::
operator () (const C_File_Pos& name) const
{
unsigned index = Element::hash(name) % size;
Element_Link* link = table[index];
while(link && ((strlen(link->element->name) != name.length)
|| strncmp(link->element->name, name.chars(), name.length)))
link = link->next;
if(link)
return link->element;
else
{ table[index] = new Element_Link(new Element (name), table[index]);
return table[index]->element;
}
}
Hierarchy& Hierarchy::
inc (Element* element)
{
unsigned index = element->hash() % size;
table[index] = new Element_Link(element, table[index]);
return *this;
}
void Hierarchy::
print (ostream& os)
{
for(unsigned index = 0; index < size; ++index)
{ for(Element_Link* link = table[index]; link; link = link->next)
{ if(!link->element->parents)
link->element->print(os, 0);
}
}
}
////////////////////////////////////////////////////////////////////////////////
inline void
parent_child (Element* parent, Element* child)
{
parent->inc_children(child);
child->inc_parents(parent);
}
Boolean
access_kw_p (const C_File_Pos& name)
{
const char* s = name.chars();
if(*s == 'p')
{
switch(name.length)
{
case 6: return !strncmp(s, "public", 6);
case 7: return !strncmp(s, "private", 7) ;
case 9: return !strncmp(s, "protected", 9);
default: return FALSE;
}
}
else if (*s == 'v')
{
switch(name.length)
{
case 7: return !strncmp(s, "virtual", 7) ;
default: return FALSE;
}
}
else
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
Hierarchy&
get_class_hier (Hierarchy& hier, const File& file)
{
C_File_Pos pos (file);
while(pos.token != END_OF_FILE)
{
switch(pos.token)
{
case CLASS_KW:
case STRUCT_KW:
pos.next_code();
if(pos.token == IDENTIFIER)
{ Element* child = hier(pos);
pos.next_code();
while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
{
if(pos.token == IDENTIFIER && !access_kw_p(pos))
{ Element* parent = hier(pos);
parent_child(parent, child);
}
pos.next_code();
}
}
else
{ while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
pos.next_code();
}
if(pos.token == OPEN_BRACE)
pos.close_brace();
break;
case UNION_KW:
case ENUM_KW:
pos.next_code();
while(pos.token != SEMI_COLON && pos.token != OPEN_BRACE && pos.token != END_OF_FILE)
pos.next_code();
if(pos.token == OPEN_BRACE)
pos.close_brace();
break;
case TYPEDEF_KW: // only catches last typedef (e.g 'c' in typedef int a, b, c;)
pos.next_code();
while(pos.token != SEMI_COLON && pos.token != END_OF_FILE)
pos.next_code();
break;
case DEFINE:
pos.close_define();
break;
case OPEN_BRACE:
pos.close_brace();
break;
case OPEN_PARE:
pos.close_pare();
break;
}
pos.next_code();
}
return hier;
}
////////////////////////////////////////////////////////////////////////////////
void
usage_error (const char* progname)
{ cerr << "Usage " << progname;
cerr << " [-a] [-f outfile] [-s num_symbols] [-k max_infile_kbytes] infile ...";
cerr << endl;
exit(BAD);
}
main (int argc, char** argv)
{
unsigned argi = 0;
char* progname = argv[argi];
// Default flags
Boolean append = FALSE;
const char* outfile = 0;
int size = 1024;
int symbols = 2000;
// Process flags
for(argi = 1; argi < argc && argv[argi][0] == '-'; ++argi)
{
switch(argv[argi][0])
{
case '?':
case 'h':
usage_error(progname);
case 'a':
append = TRUE;
break;
case 'f':
if(outfile)
{ cerr << "The -f option may only be given once." << endl;
usage_error(progname);
}
if(argv[argi][1])
outfile = &argv[argi][1];
else if(argi < argc)
outfile = argv[++argi];
else
{ cerr << "The -f option must be given an argument (the outfile name)" << endl;
usage_error(progname);
}
break;
case 'k':
if(argv[argi][1])
size = atoi(&argv[argi][1]);
else if(argi < argc)
size = atoi(argv[++argi]);
else
{ cerr << "The -k option must be given an argument (the max_file_size in kbytes)" << endl;
usage_error(progname);
}
break;
case 's':
if(argv[argi][1])
symbols = atoi(&argv[argi][1]);
else if(argi < argc)
symbols = atoi(argv[++argi]);
else
{ cerr << "The -s option must be given an argument (the expected number of symbols)" << endl;
usage_error(progname);
}
break;
default:
;
}
}
// Arg value checks
if(size < 64)
size = 64;
if(symbols < 1000)
symbols = 1000;
if(!outfile)
outfile = "CLASS.hier";
// Create File for input
File infile (size*1024);
// Create empty hierarchy
Hierarchy hier (symbols);
// Process files into hier
for(; argi < argc; ++argi)
{
infile.read(argv[argi]);
get_class_hier(hier, infile);
}
// Output hierarchy
ofstream out (outfile, (append ? ios::app : ios::out));
hier.print(out);
out << flush;
exit(GOOD);
}